package com.ajocer.springbootinit.rag;

import com.ajocer.springbootinit.model.entity.Spot;
import com.ajocer.springbootinit.model.entity.SpotRoute;
import com.ajocer.springbootinit.monitor.CachePerformanceMonitor;
import com.ajocer.springbootinit.service.SpotRouteService;
import com.ajocer.springbootinit.service.SpotService;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 旅游推荐RAG服务
 */
@Service
@Slf4j
public class TourismRagService {

    @Autowired
    private ChatLanguageModel chatLanguageModel;

    @Autowired
    private EmbeddingModel embeddingModel;

    @Autowired
    private MilvusVectorStore vectorStore;

    @Autowired
    private PromptTemplateManager promptTemplateManager;

    @Autowired
    private SpotService spotService;

    @Autowired
    private SpotRouteService spotRouteService;
    
    @Autowired
    private MultiLayerCacheService cacheService;
    
    @Autowired
    private CachePerformanceMonitor performanceMonitor;

    private static final int MAX_RESULTS = 5;
    private static final double MIN_SCORE = 0.7;

    @PostConstruct
    public void init() {
        // 加载景点数据到向量存储
        loadSpotData();
    }

    /**
     * 加载景点数据到向量存储
     */
    private void loadSpotData() {
        try {
            log.info("开始加载景点数据到向量存储");
            
            // 获取所有景点数据
            List<Spot> spots = spotService.list();
            if (spots == null || spots.isEmpty()) {
                log.warn("没有找到景点数据");
                return;
            }
            
            log.info("找到 {} 个景点", spots.size());
            
            // 将景点数据转换为文本段
            List<TextSegment> segments = new ArrayList<>();
            for (Spot spot : spots) {
                // 构建景点文档内容
                StringBuilder content = new StringBuilder();
                content.append("景点名称: ").append(spot.getSpotName()).append("\n");
                content.append("景点类型: ").append(spot.getSpotTags()).append("\n");
                content.append("景点位置: ").append(spot.getSpotLocation()).append("\n");
                content.append("景点描述: ").append(spot.getSpotDescription()).append("\n");
                
                // 创建文本段
                TextSegment segment = TextSegment.from(content.toString());
                
                segments.add(segment);
            }
            
            // 生成嵌入向量
            List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
            
            // 添加到向量存储
            vectorStore.addAll(embeddings, segments);
            
            log.info("成功加载 {} 个景点到向量存储", segments.size());
        } catch (Exception e) {
            log.error("加载景点数据到向量存储失败", e);
        }
    }

    /**
     * 根据用户偏好推荐旅游景点
     * @param userPreference 用户偏好
     * @return 推荐结果
     */
    public String recommendSpots(String userPreference) {
        String cacheKey = "spots:" + userPreference;
        boolean isCacheHit = cacheService.hasCache(cacheKey);
        long startTime = System.currentTimeMillis();
        
        String result = cacheService.getRecommendationCache(cacheKey, () -> {
            try {
                log.info("开始根据用户偏好推荐景点: {}", userPreference);
                
                // 获取相关景点内容
                List<TextSegment> relevantContent = retrieveRelevantContent(userPreference);
                
                // 构建系统提示词
                Map<String, Object> variables = promptTemplateManager.variables()
                        .with("relevantContent", formatRelevantContent(relevantContent))
                        .build();
                
                String systemPrompt = promptTemplateManager.fillTemplate("spot_recommendation_system", "1.0", variables);
                
                // 构建用户提示词
                String userPrompt = "我想要一个旅游景点推荐，我的偏好是：" + userPreference;
                
                // 发送到大模型
                Response<AiMessage> response = chatLanguageModel.generate(Arrays.asList(
                        new SystemMessage(systemPrompt),
                        new UserMessage(userPrompt)
                ));
                
                return response.content().text();
            } catch (Exception e) {
                log.error("推荐景点失败", e);
                return "抱歉，推荐景点时发生错误，请稍后再试。";
            }
        });
        
        // 记录性能数据
        long endTime = System.currentTimeMillis();
        performanceMonitor.recordRequest(isCacheHit, endTime - startTime);
        
        return result;
    }
    
    /**
     * 根据用户偏好推荐旅游路线
     * @param userPreference 用户偏好
     * @return 推荐结果
     */
    public String recommendRoutes(String userPreference) {
        String cacheKey = "routes:" + userPreference;
        boolean isCacheHit = cacheService.hasCache(cacheKey);
        long startTime = System.currentTimeMillis();
        
        String result = cacheService.getRecommendationCache(cacheKey, () -> {
            try {
                log.info("开始根据用户偏好推荐路线: {}", userPreference);
                
                // 获取相关景点内容
                List<TextSegment> relevantContent = retrieveRelevantContent(userPreference);
                
                // 获取现有路线
                List<SpotRoute> routes = spotRouteService.list();
                
                // 构建系统提示词
                Map<String, Object> variables = promptTemplateManager.variables()
                        .with("relevantContent", formatRelevantContent(relevantContent))
                        .with("existingRoutes", formatExistingRoutes(routes))
                        .build();
                
                String systemPrompt = promptTemplateManager.fillTemplate("route_recommendation_system", "1.0", variables);
                
                // 构建用户提示词
                String userPrompt = "我想要一个旅游路线推荐，我的偏好是：" + userPreference;
                
                // 发送到大模型
                Response<AiMessage> response = chatLanguageModel.generate(Arrays.asList(
                        new SystemMessage(systemPrompt),
                        new UserMessage(userPrompt)
                ));
                
                return response.content().text();
            } catch (Exception e) {
                log.error("推荐路线失败", e);
                return "抱歉，推荐路线时发生错误，请稍后再试。";
            }
        });
        
        // 记录性能数据
        long endTime = System.currentTimeMillis();
        performanceMonitor.recordRequest(isCacheHit, endTime - startTime);
        
        return result;
    }

    /**
     * 检索相关内容
     */
    private List<TextSegment> retrieveRelevantContent(String query) {
        String cacheKey = "relevant:" + query;
        boolean isCacheHit = cacheService.hasCache(cacheKey);
        long startTime = System.currentTimeMillis();
        
        List<TextSegment> result = cacheService.getQueryCache(cacheKey, () -> {
            try {
                // 生成查询向量
                Embedding queryEmbedding = embeddingModel.embed(query).content();
                
                // 从向量存储中检索相似内容
                List<EmbeddingMatch<TextSegment>> matches = vectorStore.findRelevant(queryEmbedding, MAX_RESULTS, MIN_SCORE);
                
                return matches.stream()
                        .map(EmbeddingMatch::embedded)
                        .collect(Collectors.toList());
            } catch (Exception e) {
                log.error("检索相关内容失败", e);
                return Collections.emptyList();
            }
        });
        
        // 记录性能数据
        long endTime = System.currentTimeMillis();
        performanceMonitor.recordRequest(isCacheHit, endTime - startTime);
        
        return result;
    }
    
    /**
     * 格式化相关内容
     */
    private String formatRelevantContent(List<TextSegment> segments) {
        StringBuilder sb = new StringBuilder();
        for (TextSegment segment : segments) {
            sb.append(segment.text()).append("\n\n");
        }
        return sb.toString();
    }
    
    /**
     * 格式化现有路线
     */
    private String formatExistingRoutes(List<SpotRoute> routes) {
        StringBuilder sb = new StringBuilder();
        for (SpotRoute route : routes) {
            sb.append("路线ID: ").append(route.getId()).append("\n");
            sb.append("路线描述: ").append(route.getSpotRouteDescription()).append("\n");
            sb.append("包含景点: ").append(route.getSpotIds()).append("\n\n");
        }
        return sb.toString();
    }
} 